package cn.buk.tms.bill.service;

import cn.buk.common.JsonResult;
import cn.buk.qms.BillUtil;
import cn.buk.tms.dto.TrainOrderDto;
import cn.buk.tms.dto.TrainRefundOrderDto;
import cn.buk.qms.service.BaseAbstractService;
import cn.buk.qms.service.BillServiceImpl;
import cn.buk.tms.common.constant.TmsOrderConstant;
import cn.buk.tms.dao.BillDao;
import cn.buk.tms.dao.FlightChangeOrderDao;
import cn.buk.tms.dao.FlightOrderDao;
import cn.buk.tms.dao.FlightRefundOrderDao;
import cn.buk.tms.entity.bill.*;
import cn.buk.tms.entity.misc.EntDepartment;
import cn.buk.tms.entity.order.OrderNoInfo;
import cn.buk.tms.entity.misc.RentalCarOrder;
import cn.buk.tms.entity.order.flight.*;
import cn.buk.tms.entity.order.hotel.HotelOrder;
import cn.buk.tms.entity.order.train.TrainOrder;
import cn.buk.tms.entity.order.train.TrainRefundOrder;
import cn.buk.tms.entity.order.vas.VasOrder;
import cn.buk.tms.hotel.dao.HotelOrderDao;
import cn.buk.tms.train.dao.TrainOrderDao;
import cn.buk.tms.train.dao.TrainRefundOrderDao;
import cn.buk.common.util.DateUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

import static cn.buk.tms.common.constant.TmsOrderConstant.*;

@Service
public class BillImportServiceImpl extends BaseAbstractService implements BillImportService {

  private static final Logger logger = LogManager.getLogger(BillServiceImpl.class);

  @Autowired
  private BillDao billDao;

  @Autowired
  private FlightOrderDao flightOrderDao;

  @Autowired
  private FlightRefundOrderDao flightRefundOrderDao;

  @Autowired
  private FlightChangeOrderDao flightChangeOrderDao;

  @Autowired
  private HotelOrderDao hotelOrderDao;

  @Autowired
  private TrainOrderDao trainOrderDao;

  @Autowired
  private TrainRefundOrderDao trainRefundOrderDao;

  private static final  String ERROR_MESSAGE_ALREADY_IMPORTED = "已导入过";

  @Override
  public JsonResult importFlightOrder(final int enterpriseId, final String username, final int orderId) {
    var flightOrder = flightOrderDao.getOrderDetailById(orderId);
    if (flightOrder == null || flightOrder.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-1, "无此机票订单");
    }

    if (flightOrder.getStatus() != TmsOrderConstant.FLIGHT_ORDER_STATUS_FINISHED) {
      return JsonResult.createJsonResult(-2, "机票订单状态不是已完成状态");
    }

    // 检查是否已导入过
    List<BillInfo> billInfos = billDao.searchBillInfos(enterpriseId, orderId);
    if (!billInfos.isEmpty()) {
      return JsonResult.createJsonResult(-3, ERROR_MESSAGE_ALREADY_IMPORTED);
    }

    BillInfo billInfo = convertFlightOrderToBillInfo(flightOrder);
    billInfo.setOperator(username);

    int retCode;
    try {
      retCode = billDao.createFlightBill(billInfo, orderId);
    } catch (RuntimeException ex) {
      for (BillFlightTicket ticket : billInfo.getTickets()) {
        logger.error(ticket.getTicketNo());
      }
      logger.error(ex.getMessage());
      retCode = -100;
      ex.printStackTrace();
    }

    if (retCode < 0) {
      //如果导入不成功，发送提醒，找找原因
      String content = "机票订单(" + flightOrder.getOrderNo() + ") 输出为账单时失败！";
      doSendAlert(flightOrder.getEnterpriseId(), content, null, EntDepartment.DEPT_ADMINISTRATOR);
    }

    return JsonResult.createJsonResult(retCode);
  }


  /**
   * 将机票订单转化为账单
   */
  @Override
  public BillInfo convertFlightOrderToBillInfo(FlightOrder o) {
    BillInfo b = new BillInfo();

    b.setBillType(BILL_TYPE_FLIGHT);
    b.setEnterpriseId(o.getEnterpriseId());
    b.setFlightOrderId(o.getId());
    b.setOrderNo(o.getOrderNo());
    b.setFlightOrderNo(o.getOrderNo()); // 冗余：方便已订单号统一查找出票、退票、改签、服务账单

    final String billNum = orderNoGenerator
            .generateOrderNo(o.getEnterpriseId(), OrderNoInfo.BILL_FLIGHT);

    b.setBillNum(billNum);
    b.setOpDate(DateUtil.getCurDate());
    b.setEtdzDate(o.getEtdzDate());

    b.setBillSum(o.getTotalAmount());
    b.setCost(o.getTotalCost());
    b.setProfit(o.getProfit());

    //放在setBillCustomerInfo之前，在setBillCustomerInfo中某些情况下需要用到costCenter
    b.setCostCenter(o.getCostCenter()); // 成本中心
    b.setProjectName(o.getProjectName()); // 项目名称

    // 如果是(散客)企业，则账单变为散客
    BillUtil.setBillCustomerInfo(b, o.getCustomerType(), o.getLinkman(), o.getLinkPhone(), o.getCustomer());

    b.setSupplier(o.getSupplier());
    b.setPaymentMethod(o.getPaymentMethod());

    b.setOp1(o.getOperator());
    b.setOp2(o.getTicketer());
    b.setOp3(o.getCashier());

    b.setPayTypeNote(o.getPayType() + "");
    b.setPayRemark(o.getPayRemark());

    b.setIntlTicket(o.getIntlTicket()); // 国内国际

    b.setRemark(o.getRemark()); // 订单的备注导入到账单备注

    if (o.getPassengers().isEmpty()) {
      throw new RuntimeException("No passenger.");
    }
    for (FlightOrderPassenger psg : o.getPassengers()) {
      BillFlightTicket ticket = new BillFlightTicket();
      b.getTickets().add(ticket);

      ticket.setEnterpriseId(b.getEnterpriseId());
      ticket.setBillNum(billNum);
      ticket.setPassengerName(psg.getName());

      ticket.setTicketNo(psg.getTicketNo());
      ticket.setTicketNoEnd(psg.getTicketNoEnd());
      ticket.setTicketCount(psg.getTicketCount());

      ticket.setSaleDate(b.getOpDate());
      ticket.setOrderDate(o.getCreateDate());

      ticket.setCustomer(b.getCustomer());

      if (psg.getPsgType() == 0) {
        // adult
        ticket.setPrice(o.getPrice());
        ticket.setParvalue(o.getParvalue());
        ticket.setTax(o.getTax());
        ticket.setCommission(o.getCommission() + o.getCommission2());
        ticket.setDiscount(o.getDiscount());
        ticket.setServiceCharge(o.getServiceCharge());
        ticket.setInsurance(o.getInsurance());
        ticket.setAccountRecv(o.getAmount());

        //TODO 这个计算是否少算了discount的内容 yfdai 2021-01-21
        double cost = o.getParvalue() + o.getTax() + o.getInsurance() - o.getCommission() - o.getCommission2();
        ticket.setCost(cost);
        ticket.setProfit(o.getAmount() - cost);
      } else if (psg.getPsgType() == 1) {
        // child
        ticket.setPrice(o.getChdPrice());
        ticket.setParvalue(o.getChdParvalue());
        ticket.setTax(o.getChdTax());
        ticket.setCommission(o.getChdCommission() + o.getChdCommission2());
        ticket.setDiscount(o.getChdDiscount());
        ticket.setServiceCharge(o.getChdServiceCharge());
        ticket.setInsurance(o.getChdInsurance());
        ticket.setAccountRecv(o.getChdAmount());

        double cost =
                o.getChdParvalue() + o.getChdTax() + o.getChdInsurance() - o.getChdCommission() - o.getChdCommission2();
        ticket.setCost(cost);
        ticket.setProfit(o.getChdAmount() - cost);
      } else if (psg.getPsgType() == 2) {
        // infant
        ticket.setPrice(o.getInfPrice());
        ticket.setParvalue(o.getInfParvalue());
        ticket.setTax(o.getInfTax());
        ticket.setCommission(o.getInfCommission() + o.getInfCommission2());
        ticket.setDiscount(o.getInfDiscount());
        ticket.setServiceCharge(o.getInfServiceCharge());
        ticket.setInsurance(o.getInfInsurance());
        ticket.setAccountRecv(o.getInfAmount());

        double cost =
                o.getInfParvalue() + o.getInfTax() + o.getInfInsurance() - o.getInfCommission() - o.getInfCommission2();
        ticket.setCost(cost);
        ticket.setProfit(o.getInfAmount() - cost);
      } else {
        throw new RuntimeException("not implemented.");
      }

      ticket.setEtdzDate(o.getEtdzDate());

      // 冗余的航班信息
      ticket.setRouteDetail(o.getRouteDetail());

      ticket.setPnrNo(o.getPnrNo());

      if (o.getFlights().isEmpty()) {
        throw new RuntimeException("Flights is empty.");
      }
      for (FlightOrderFlight flt : o.getFlights()) {
        BillFlightTicketDetail detail = new BillFlightTicketDetail();
        ticket.getDetails().add(detail);

        detail.setEnterpriseId(flt.getEnterpriseId());
        detail.setSegOrd(flt.getSegOrder() + "");
        detail.setDport(flt.getFlight().getDepartureAirport());
        detail.setDportName(flt.getFlight().getDepartureAirportName());
        detail.setDterm(flt.getFlight().getDepartureTerminal());
        detail.setAport(flt.getFlight().getArrivalAirport());
        detail.setAportName(flt.getFlight().getArrivalAirportName());
        detail.setAterm(flt.getFlight().getArrivalTerminal());
        detail.setSubclass(flt.getFlight().getSubclass());
        detail.setFlight(flt.getFlight().getFlightNo());
        detail.setCarrier(flt.getFlight().getFlightNo().substring(0, 2));
        detail.setDdate(flt.getFlight().getDepartureDate());
        detail.setDtime(flt.getFlight().getDepartureTime());
        detail.setAtime(flt.getFlight().getArrivalTime());

        detail.setBalanceCode(ticket.getBalanceCode());
        detail.setTicketNo(ticket.getTicketNo());
      }
    }

    b.setTicketCount(b.getTickets().size()); // set ticket_count

    return b;
  }

  /**
   * 将退票单导入账单
   *
   * @param enterpriseId 企业id
   * @param id           退票单id
   */
  @Override
  public JsonResult importFlightRefundOrder(int enterpriseId, String username, int id) {
    FlightRefundOrder order = flightRefundOrderDao.getFlightRefundOrderDetail(id);
    if (order == null || order.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-1, "无此退票单");
    }

    if (order.getStatus() != FlightRefundOrder.ORDER_STATUS_DONE) {
      logger.warn("FlightRefundOrder is not done.");
      return JsonResult.createJsonResult(-2, "退票单状态不是已完成状态");
    }

    // 检查是否已导入过
    List<BillInfo> billInfos = billDao
            .searchBillInfos(enterpriseId, order.getRefundOrderNo(), BILL_TYPE_FLIGHT_REFUND);
    if (!billInfos.isEmpty()) {
      return JsonResult.createJsonResult(-3, ERROR_MESSAGE_ALREADY_IMPORTED);
    }

    BillInfo billInfo = convertFlightRefundOrderToBillInfo(order);
    billInfo.setOperator(username);

    int retCode;

    try {
      retCode = billDao.createFlightRefundBill(billInfo);
    } catch (RuntimeException ex) {
      logger.error(ex.getMessage());
      retCode = -100;
    }

    if (retCode < 0) {
      String content = "退票订单(" + order.getRefundOrderNo() + ") 输出为账单时失败！";
      doSendAlert(order.getEnterpriseId(), content, null, EntDepartment.DEPT_ADMINISTRATOR);
    }

    return JsonResult.createJsonResult(retCode);
  }


  /**
   * 将退票单转换为账单 退票账单的金额用负数：
   */
  @Override
  public BillInfo convertFlightRefundOrderToBillInfo(FlightRefundOrder o) {
    BillInfo b = new BillInfo();

    b.setEnterpriseId(o.getEnterpriseId());
    b.setBillType(BILL_TYPE_FLIGHT_REFUND);
    b.setOrderNo(o.getRefundOrderNo()); //退票账单中的订单号是对应的退票订单的退票单号
    b.setFlightOrderNo(o.getOrderNo()); //保存关联的机票订单号

    final String billNum = orderNoGenerator
            .generateOrderNo(o.getEnterpriseId(), OrderNoInfo.BILL_FLIGHT_REFUND);

    b.setBillNum(billNum);
    b.setOpDate(DateUtil.getCurDate());

    final double billSum = o.getPassengerRefundAmount() == null ? 0 : o.getPassengerRefundAmount();
    b.setBillSum(-billSum);
    if (o.getAirlineRefundAmount() == null) {
      b.setCost(0d);
      b.setProfit(0d - billSum);
    } else {
      b.setCost(-o.getAirlineRefundAmount());
      b.setProfit(o.getAirlineRefundAmount() - billSum);
    }

    //退票日期用退票单生成日期
    b.setEtdzDate(o.getCreateTime());

    b.setAudited(BILL_NOT_AUDITED); // 退票账单默认为未审核

    b.setCostCenter(o.getCostCenter()); //成本中心
    // 从机票订单中获取"项目名称"; 成本中心也在这里获取？
    FlightOrder fltOrder = flightOrderDao.getOrderDetailByOrderNo(o.getEnterpriseId(), o.getOrderNo());
    if (fltOrder != null) {
      b.setProjectName(fltOrder.getProjectName());
    }

    BillUtil.setBillCustomerInfo(b, o.getCustomerType(), o.getLinkman(), o.getLinkPhone(), o.getCustomer());

    b.setPayTypeNote(o.getPayType() + "");
    b.setPayRemark(o.getPayRemark());

    b.setSupplier(o.getSupplier());
    b.setPaymentMethod(o.getPaymentMethod());

    b.setOp1(o.getOperator());
    b.setOp2(o.getTicketer());
    b.setOp3(o.getCashier());

    b.setPayTypeNote(o.getPayType() + ""); //客户的付款方式

    b.setIntlTicket(o.getIntlTicket()); // 国内国际

    b.setRemark(o.getRemark()); // 订单备注

    BillFlightRefundTicket refundTicket = new BillFlightRefundTicket();
    b.getRefundTickets().add(refundTicket);

    refundTicket.setEnterpriseId(o.getEnterpriseId());
    refundTicket.setBillNum(billNum);
    refundTicket.setCustomer(o.getCustomer());
    refundTicket.setCustomerType(o.getCustomerType());

    refundTicket.setPsgName(o.getPsgName());
    refundTicket.setPnrNo(o.getPnrNo());
    refundTicket.setBalanceCode(o.getBalanceCode());
    refundTicket.setTicketNo(o.getTicketNo());
    refundTicket.setTicketAmount(o.getTicketAmount());
    refundTicket.setServiceCharge(o.getServiceCharge());
    refundTicket.setAirRefundCharge(o.getAirRefundCharge());

    final double psgRefundAmount =
            o.getPassengerRefundAmount() == null ? 0 : o.getPassengerRefundAmount();
    refundTicket.setPassengerRefundAmount(psgRefundAmount);

    final double airRefundAmount =
            o.getAirlineRefundAmount() == null ? 0 : o.getAirlineRefundAmount();
    refundTicket.setAirlineRefundAmount(airRefundAmount);

    refundTicket.setStatus(o.getStatus());

    refundTicket.setOperator(o.getOperator());
    refundTicket.setTicketer(o.getTicketer());
    refundTicket.setCashier(o.getCashier());

    refundTicket.setStatus(o.getStatus());

    refundTicket.setIntlTicket(o.getIntlTicket());

    refundTicket.setRefundOrderNo(o.getRefundOrderNo());
    refundTicket.setOrderNo(o.getOrderNo());

    refundTicket.setReasonCode(o.getReasonCode());
    refundTicket.setReasonDesc(o.getReasonDesc());

    refundTicket.setSubmitDate(o.getSubmitDate());
    refundTicket.setAirlineRefundDate(o.getAirlineRefundDate());
    refundTicket.setPsgRefundDate(o.getPsgRefundDate());

    refundTicket.setOrderDate(o.getCreateTime());

    String remark = null;
    for (FlightRefundOrderDetail detail : o.getFlights()) {
      if (remark == null) {
        remark = detail.getFlight().getRouteDetail();
      } else {
        remark += "//" + detail.getFlight().getRouteDetail();
      }
    }

    refundTicket.setRemark(remark);

    b.setTicketCount(1); // set ticket_count

    return b;
  }


  @Override
  public BillInfo convertFlightChangeOrderToBillInfo(FlightChangeOrder o) {
    BillInfo b = new BillInfo();

    b.setEnterpriseId(o.getEnterpriseId());
    b.setBillType(BILL_TYPE_FLIGHT_CHANGE);
    b.setOrderNo(o.getChangeOrderNo()); //退票账单中的订单号是对应的退票订单的退票单号
    b.setFlightOrderNo(o.getOrderNo());

    final String billNum = orderNoGenerator
            .generateOrderNo(o.getEnterpriseId(), OrderNoInfo.BILL_FLIGHT_CHANGE);

    b.setBillNum(billNum);
    b.setOpDate(DateUtil.getCurDate());

    b.setBillSum(o.getServiceCharge() + o.getAirChangeCharge());
    b.setCost(o.getAirChangeCharge());
    b.setProfit(o.getServiceCharge());

    //改签日期用改签单生成日期
    b.setEtdzDate(o.getCreateTime());

    b.setCostCenter(o.getCostCenter()); //成本中心
    b.setProjectName(o.getProjectName());

    // 如果是(散客)企业，则账单变为散客
    BillUtil.setBillCustomerInfo(b, o.getCustomerType(), o.getLinkman(), o.getLinkPhone(), o.getCustomer());

    b.setSupplier(o.getSupplier());
    b.setPaymentMethod(o.getPaymentMethod());

    b.setOp1(o.getOperator());
    b.setOp2(o.getTicketer());
    b.setOp3(o.getCashier());

    b.setPayTypeNote(o.getPayType() + ""); //客户的付款方式

    b.setIntlTicket(o.getIntlTicket()); // 国内国际
    b.setRemark(o.getRemark()); //订单备注

    // 账单包含的增值服务单内容
    BillChangeOrder billChangeOrder = new BillChangeOrder();
    b.getChangeOrders().add(billChangeOrder);

    BeanUtils.copyProperties(o, billChangeOrder);
    billChangeOrder.setBillNum(billNum);
    billChangeOrder.setId(0);

    String remark = null;
    for (FlightChangeOrderDetail detail : o.getFlights()) {
      if (remark == null) {
        remark = detail.getFlight().getRouteDetail() + "/" + detail.getFlightType();
      } else {
        remark += "//" + detail.getFlight().getRouteDetail() + "/" + detail.getFlightType();
      }
    }
    billChangeOrder.setRemark(remark);
    billChangeOrder.setOrderDate(o.getCreateTime());

    b.setTicketCount(1); // set ticket_count

    return b;
  }



  @Override
  public JsonResult importFlightChangeOrder(final int enterpriseId, final String username,
                                            final int id) {
    FlightChangeOrder order = flightChangeOrderDao.getFlightChangeOrderDetail(id);
    if (order == null || order.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-1, "无此改签单");
    }

    if (order.getStatus() != FlightChangeOrder.ORDER_STATUS_FINISHED) {
      logger.warn("FlightChangeOrder is not done.");
      return JsonResult.createJsonResult(-2, "改签单状态不是已完成状态");
    }

    // 检查是否已导入过
    List<BillInfo> billInfos = billDao
            .searchBillInfos(enterpriseId, order.getChangeOrderNo(), BILL_TYPE_FLIGHT_CHANGE);
    if (!billInfos.isEmpty()) {
      return JsonResult.createJsonResult(-3, ERROR_MESSAGE_ALREADY_IMPORTED);
    }

    BillInfo billInfo = convertFlightChangeOrderToBillInfo(order);
    billInfo.setOperator(username);

    int retCode;
    try {
      retCode = billDao.createFlightChangeBill(billInfo);
    } catch (RuntimeException ex) {
      logger.error(ex.getMessage());
      retCode = -100;
    }

    logger.info(retCode);
    if (retCode < 0) {
      String content = "改签订单(" + order.getChangeOrderNo() + ") 输出为账单时失败！";
      doSendAlert(order.getEnterpriseId(), content, null, EntDepartment.DEPT_ADMINISTRATOR);
    }

    return JsonResult.createJsonResult(retCode);
  }


  @Override
  public BillInfo convertVasOrderToBillInfo(VasOrder o) {
    BillInfo b = new BillInfo();

    b.setBillType(BILL_TYPE_VAS);
    b.setEnterpriseId(o.getEnterpriseId());
    b.setFlightOrderId(o.getId());
    b.setOrderNo(o.getOrderNo());

    FlightOrder fltOrder = flightOrderDao.getOrderDetailById(o.getFlightOrderId());
    if (fltOrder == null || fltOrder.getEnterpriseId() != o.getEnterpriseId()) {
      fltOrder = null;
    }

    if (fltOrder != null) {
      b.setFlightOrderNo(fltOrder.getOrderNo());
    }

    final String billNum = orderNoGenerator
            .generateOrderNo(o.getEnterpriseId(), OrderNoInfo.BILL_VAS);

    b.setBillNum(billNum);
    b.setOpDate(DateUtil.getCurDate());

    final double billSum = o.getCount() * (o.getPrice() - o.getDiscount());
    b.setBillSum(billSum);

    final double totalCost = o.getCount() * o.getCost();
    b.setCost(totalCost);

    final double profit = o.getCount() * (o.getPrice() - o.getDiscount() - o.getCost());
    b.setProfit(profit);

    // 如果是(散客)企业，则账单变为散客
    if (fltOrder != null) {
      b.setCostCenter(fltOrder.getCostCenter());
      b.setProjectName(fltOrder.getProjectName());
    }

    BillUtil.setBillCustomerInfo(b, o.getCustomerType(), o.getLinkman(), o.getLinkPhone(), o.getCustomer());

    if (o.getCostCenter() != null && o.getCostCenter().trim().length() > 0) {
      b.setCostCenter(o.getCostCenter().trim());
    }

    if (o.getProjectName() != null && o.getProjectName().trim().length() > 0) {
      b.setProjectName(o.getProjectName().trim());
    }

    b.setSupplier(o.getSupplier());
    b.setPaymentMethod(o.getPaymentMethod());

    b.setOp1(o.getOperator());
    b.setOp2(o.getTicketer());

    b.setPayTypeNote(o.getPayType() + "");

    // 订单备注
    b.setRemark(o.getRemark());

    // 账单包含的增值服务单内容
    BillVasOrder billVasOrder = new BillVasOrder();
    BeanUtils.copyProperties(o, billVasOrder);
    billVasOrder.setBillNum(billNum);

    billVasOrder.setId(0);
    billVasOrder.setTotal(billSum);
    billVasOrder.setCost(totalCost);
    billVasOrder.setProfit(profit);

    billVasOrder.setOrderDate(o.getCreateDate());

    b.getVasOrders().add(billVasOrder);

    // set ticket_count
    b.setTicketCount(1);

    return b;
  }


  @Override
  public JsonResult importVasOrder(int enterpriseId, String username, int orderId) {
    VasOrder order = vasOrderDao.getOrderById(orderId);
    if (order == null || order.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-1, "无此服务单");
    }

    if (order.getStatus() != TmsOrderConstant.ORDER_STATUS_DONE) {
      logger.warn("FlightRefundOrder is not done.");
      return JsonResult.createJsonResult(-2, "服务单状态不是已完成状态");
    }

    // 检查是否已导入过
    List<BillInfo> billInfos = billDao
            .searchBillInfos(enterpriseId, order.getOrderNo(), BILL_TYPE_VAS);
    if (!billInfos.isEmpty()) {
      return JsonResult.createJsonResult(-3, ERROR_MESSAGE_ALREADY_IMPORTED);
    }

    BillInfo billInfo = convertVasOrderToBillInfo(order);
    billInfo.setOperator(username);

    int retCode;
    try {
      retCode = billDao.createVasBill(billInfo);
    } catch (RuntimeException ex) {
      logger.error(ex.getMessage());
      retCode = -100;
    }

    logger.info(retCode);
    if (retCode < 0) {
      String content = "服务订单(" + order.getOrderNo() + ") 输出为账单时失败！";
      doSendAlert(order.getEnterpriseId(), content, null, EntDepartment.DEPT_ADMINISTRATOR);
    }

    return JsonResult.createJsonResult(retCode);
  }



  /**
   * 导入酒店订单
   */
  @Override
  public JsonResult importHotelOrder(final int enterpriseId, final String username,
                                     final int orderId) {
    HotelOrder order = hotelOrderDao.getHotelOrderById(orderId);
    if (order == null || order.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-1, "无此酒店订单单、");
    }

    if (order.getStatus() != TmsOrderConstant.HOTEL_ORDER_STATUS_DONE) {
      logger.warn("HotelOrder is not done.");
      return JsonResult.createJsonResult(-2, "订单不是已完成状态");
    }

    // 检查是否已导入过
    List<BillInfo> billInfos = billDao
            .searchBillInfos(enterpriseId, order.getOrderNo(), BILL_TYPE_HOTEL);
    if (!billInfos.isEmpty()) {
      return JsonResult.createJsonResult(-3, ERROR_MESSAGE_ALREADY_IMPORTED);
    }

    BillInfo billInfo = convertHotelOrderToBillInfo(order);
    billInfo.setOperator(username);

    int retCode;
    try {
      retCode = billDao
              .createHotelBooking(enterpriseId, username, billInfo.getHotelBookings().get(0), billInfo);
    } catch (RuntimeException ex) {
      logger.error(ex.getMessage());
      retCode = -100;
    }

    logger.info(retCode);
    if (retCode < 0) {
      String content = "酒店订单(" + order.getOrderNo() + ") 输出为账单时失败！";
      doSendAlert(order.getEnterpriseId(), content, null, EntDepartment.DEPT_ADMINISTRATOR);
    }

    return JsonResult.createJsonResult(retCode);
  }

  /**
   * 导入火车票账单
   */
  @Override
  public JsonResult importTrainOrder(int enterpriseId, String username, int orderId) {
    TrainOrder order = trainOrderDao.getTrainOrderById(orderId);
    if (order == null || order.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-1, "无此订单");
    }

    if (order.getStatus() != TrainOrder.STATUS_DONE) {
      logger.warn("TrainOrder is not done.");
      return JsonResult.createJsonResult(-2, "订单不是已完成状态");
    }

    // 检查是否已导入过
    List<BillInfo> billInfos = billDao
            .searchBillInfos(enterpriseId, order.getOrderNo(), BILL_TYPE_TRAIN);
    if (!billInfos.isEmpty()) {
      return JsonResult.createJsonResult(-3, ERROR_MESSAGE_ALREADY_IMPORTED);
    }

    BillInfo billInfo = convertTrainOrderToBillInfo(order);
    billInfo.setOperator(username);

    int retCode;
    try {
      retCode = billDao
              .createTrainTicket(enterpriseId, username, billInfo.getTrainTickets().get(0), billInfo);
    } catch (RuntimeException ex) {
      logger.error(ex.getMessage());
      retCode = -100;
    }

    logger.info(retCode);
    if (retCode < 0) {
      String content = "酒店订单(" + order.getOrderNo() + ") 输出为账单时失败！";
      doSendAlert(order.getEnterpriseId(), content, null, EntDepartment.DEPT_ADMINISTRATOR);
    }

    return JsonResult.createJsonResult(retCode);
  }

  @Override
  public JsonResult importTrainRefundOrder(final int enterpriseId, final String username, final int orderId) {
    TrainRefundOrder order = trainRefundOrderDao.getOrderById(orderId);
    if (order == null || order.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-1, "无此订单");
    }

    if (order.getStatus() != TrainOrder.STATUS_DONE) {
      logger.warn("TrainRefundOrder is not done.");
      return JsonResult.createJsonResult(-2, "订单不是已完成状态");
    }

    // 检查是否已导入过
    List<BillInfo> billInfos = billDao
            .searchBillInfos(enterpriseId, order.getOrderNo(), BILL_TYPE_TRAIN);
    if (!billInfos.isEmpty()) {
      return JsonResult.createJsonResult(-3, ERROR_MESSAGE_ALREADY_IMPORTED);
    }

    BillInfo billInfo = convertTrainRefundOrderToBillInfo(order);
    billInfo.setOperator(username);

    int retCode;
    try {
      retCode = billDao
              .createTrainTicket(enterpriseId, username, billInfo.getTrainTickets().get(0), billInfo);
    } catch (RuntimeException ex) {
      logger.error(ex.getMessage());
      retCode = -100;
    }

    logger.info(retCode);
    if (retCode < 0) {
      String content = "火车退票单(" + order.getOrderNo() + ") 输出为账单时失败！";
      doSendAlert(order.getEnterpriseId(), content, null, EntDepartment.DEPT_ADMINISTRATOR);
    }

    return JsonResult.createJsonResult(retCode);
  }

  /**
   * 将酒店订单转化为账单
   *
   * @param o Hotel Order
   */
  @Override
  public BillInfo convertHotelOrderToBillInfo(HotelOrder o) {
    BillInfo b = new BillInfo();

    b.setBillType(BILL_TYPE_HOTEL);
    b.setEnterpriseId(o.getEnterpriseId());

    final String billNum = orderNoGenerator
            .generateOrderNo(o.getEnterpriseId(), OrderNoInfo.BILL_HOTEL);
    b.setBillNum(billNum);
    b.setOrderNo(o.getOrderNo());
    b.setOpDate(DateUtil.getCurDate());

    b.setOperator(o.getOperator());
    b.setOp1(o.getOperator());
    b.setOp2(o.getTicketer());

    b.setPayTypeNote(o.getPayType() + "");

    b.setSupplier(o.getSupplier());
    b.setPaymentMethod(o.getPaymentMethod());

    BillUtil.setBillCustomerInfo(b, o.getCustomerType(), null, null, o.getCustomer());

    //成本中心
    b.setCostCenter(o.getCostCenter());
    //项目名称
    b.setProjectName(o.getProjectName());

    b.setBillSum(o.getTotalAmount());
    b.setCost(o.getTotalCost());
    b.setProfit(o.getProfit());

    // Hotel booking
    BillHotelBooking hb = new BillHotelBooking();
    b.getHotelBookings().add(hb);

    BeanUtils.copyProperties(o, hb);

    hb.setId(0);
    hb.setDdate(o.getCheckInDate());
    hb.setLeaveDate(o.getCheckOutDate());
    hb.setSaleDate(DateUtil.getCurDate());

    hb.setBillNum(billNum);

    return b;
  }

  /**
   * 火车票订单转化为账单
   */
  @Override
  public BillInfo convertTrainOrderToBillInfo(TrainOrder o) {
    BillInfo b = new BillInfo();

    b.setBillType(BILL_TYPE_TRAIN);
    b.setEnterpriseId(o.getEnterpriseId());

    final String billNum = orderNoGenerator
            .generateOrderNo(o.getEnterpriseId(), OrderNoInfo.BILL_TRAIN);
    b.setBillNum(billNum);
    b.setOrderNo(o.getOrderNo());
    b.setOpDate(DateUtil.getCurDate());

    b.setOperator(o.getOperator());
    b.setOp1(o.getOperator());
    b.setOp2(o.getTicketer());

    b.setPayTypeNote(o.getPayType() + "");

    b.setSupplier(o.getSupplier());
    b.setPaymentMethod(o.getPaymentMethod());

    BillUtil.setBillCustomerInfo(b, o.getCustomerType(), null, null, o.getCustomer());
    b.setCostCenter(o.getCostCenter());
    b.setProjectName(o.getProjectName());

    b.setBillSum(o.getTotalAmount());
    b.setCost(o.getTotalCost());
    b.setProfit(o.getProfit());

    // Train booking
    BillTrainTicket tt = new BillTrainTicket();
    b.getTrainTickets().add(tt);

    BeanUtils.copyProperties(o, tt);
    tt.setSaleDate(DateUtil.getCurDate());

    tt.setId(0);
    tt.setDdate(o.getDdate());

    tt.setBillNum(billNum);

    TrainOrderDto dto = TrainOrderDto.createByTrainOrder(o);
    dto.processPassengerInfo();
    if (dto.getPassengerName() != null) {
      tt.setPassengerName(dto.getPassengerName());
      tt.setPsgCount(dto.getPsgCount());
    }

    return b;
  }

  /**
   * 火车票退票单转化为账单
   */
  private BillInfo convertTrainRefundOrderToBillInfo(TrainRefundOrder o) {
    BillInfo b = new BillInfo();

    b.setBillType(BILL_TYPE_TRAIN);
    b.setEnterpriseId(o.getEnterpriseId());

    final String billNum = orderNoGenerator
            .generateOrderNo(o.getEnterpriseId(), OrderNoInfo.BILL_TRAIN);
    b.setBillNum(billNum);
    b.setOrderNo(o.getOrderNo());
    b.setFlightOrderNo(o.getTrainOrderNo()); //退票单所对应的订单
    b.setOpDate(DateUtil.getCurDate());

    b.setOperator(o.getOperator());
    b.setOp1(o.getOperator());
    b.setOp2(o.getTicketer());

    b.setPayTypeNote(o.getPayType() + "");

    b.setSupplier(o.getSupplier());
    b.setPaymentMethod(o.getPaymentMethod());

    BillUtil.setBillCustomerInfo(b, o.getCustomerType(), null, null, o.getCustomer());
    b.setCostCenter(o.getCostCenter());
    b.setProjectName(o.getProjectName());

    b.setRemark("火车退票");
    b.setBillSum(-o.getTotalCost());
    b.setCost(-o.getTotalAmount());
    b.setProfit(o.getProfit());

    // Train booking
    BillTrainTicket tt = new BillTrainTicket();
    b.getTrainTickets().add(tt);

    BeanUtils.copyProperties(o, tt);
    tt.setSaleDate(DateUtil.getCurDate());

    tt.setId(0);
    tt.setDdate(o.getDdate());

    tt.setBillNum(billNum);
    tt.setRemark("退票");
    //退票对应的账单是给客人看的
    tt.setPrice(-o.getCost());
    tt.setCost(-o.getPrice());


    TrainRefundOrderDto dto = TrainRefundOrderDto.createByOrder(o);
    dto.processPassengerInfo();
    if (dto.getPassengerName() != null) {
      tt.setPassengerName(dto.getPassengerName());
      tt.setPsgCount(dto.getPsgCount());
    }

    return b;
  }


  @Override
  public JsonResult importRentalCarOrder(final int enterpriseId, final String username, final int orderId) {
    RentalCarOrder orderInfo = carOrderDao.getOrderById(orderId);
    if (orderInfo == null || orderInfo.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-404, "无此订单");
    }

    if (orderInfo.getStatus() != TmsOrderConstant.RENTAL_CAR_ORDER_STATUS_DONE) {
      logger.warn("Rental car order is not done.");
      return JsonResult.createJsonResult(-2, "订单状态不是已完成");
    }

    // 检查是否已导入过
    List<BillInfo> billInfos = billDao.searchBillInfos(enterpriseId, orderInfo.getOrderNo(), BILL_TYPE_CAR);
    if (!billInfos.isEmpty()) {
      return JsonResult.createJsonResult(-3, ERROR_MESSAGE_ALREADY_IMPORTED);
    }

    BillInfo billInfo = convertRentalCarOrderToBillInfo(orderInfo);
    billInfo.setOperator(username);

    int retCode;
    try {
      retCode = billDao.createRentalCarBill(billInfo, orderId);
    } catch (RuntimeException ex) {

      logger.error(ex.getMessage());
      retCode = -100;
      ex.printStackTrace();
    }

    //如果导入不成功，发送提醒，找找原因
    if (retCode < 0) {
      String content = "租车订单(" + orderInfo.getOrderNo() + ") 输出为账单时失败！";
      doSendAlert(orderInfo.getEnterpriseId(), content, null, EntDepartment.DEPT_ADMINISTRATOR);
    }

    return JsonResult.createJsonResult(retCode);
  }


  /**
   * 将租车订单信息转换为对应的账单信息
   */
  private BillInfo convertRentalCarOrderToBillInfo(RentalCarOrder o) {
    BillInfo b = new BillInfo();

    b.setBillType(BILL_TYPE_CAR);
    b.setEnterpriseId(o.getEnterpriseId());

    final String billNum = orderNoGenerator
            .generateOrderNo(o.getEnterpriseId(), OrderNoInfo.BILL_RENTAL_CAR);
    b.setBillNum(billNum);
    b.setOrderNo(o.getOrderNo());
    b.setOpDate(DateUtil.getCurDate());

    b.setOperator(o.getOperator());
    b.setOp1(o.getOperator());
    b.setOp2(o.getTicketer());

    b.setPayTypeNote(o.getPayType() + "");

    b.setSupplier(o.getSupplier());
    b.setPaymentMethod(o.getPaymentMethod());

    BillUtil.setBillCustomerInfo(b, o.getCustomerType(), null, null, o.getCustomer());
    b.setCostCenter(o.getCostCenter());
    b.setProjectName(o.getProjectName());

    b.setRemark(o.getRemark());
    b.setBillSum(o.getPrice() - o.getDiscount() + o.getServiceCharge());
    b.setCost(o.getCost());
    b.setProfit(o.getProfit());

    // Rental Car
    BillRentalCarOrder tt = new BillRentalCarOrder();
    b.getCarOrders().add(tt);
    BeanUtils.copyProperties(o, tt);

    tt.setId(0);
    tt.setBillNum(billNum);
    tt.setOrderDate(o.getCreateDate());

    tt.setLinkman(o.getName());
    tt.setRemark(o.getRemark());

    tt.setPrice(o.getPrice());
    tt.setDiscount(o.getDiscount());
    tt.setServiceCharge(o.getServiceCharge());
    tt.setCost(o.getCost());
    tt.setTotal(o.getPrice() - o.getDiscount());
    tt.setProfit(o.getProfit());

    return b;
  }

}
